Skip to content

feat: implement HTTP allowed hosts/origins checking #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 11, 2025

Conversation

hugodutka
Copy link
Collaborator

@hugodutka hugodutka commented Aug 6, 2025

This PR adds 2 new CLI flags: --allowed-hosts and --allowed-origins. They control what kinds of Host and Origin headers the server accepts.

@hugodutka hugodutka force-pushed the hugodutka/allowed-hosts branch 3 times, most recently from 87cefa1 to 85834d5 Compare August 6, 2025 18:11
@hugodutka hugodutka changed the title feat: add the --allowed-hosts CLI flag feat: implement HTTP allowed hosts checking Aug 6, 2025
@hugodutka hugodutka force-pushed the hugodutka/allowed-hosts branch from 85834d5 to e2c72e6 Compare August 7, 2025 14:19
@hugodutka hugodutka force-pushed the hugodutka/allowed-hosts branch from e2c72e6 to f1b18a2 Compare August 7, 2025 14:43
@hugodutka hugodutka changed the title feat: implement HTTP allowed hosts checking feat: implement HTTP allowed hosts/origins checking Aug 7, 2025
@hugodutka hugodutka marked this pull request as ready for review August 7, 2025 14:45
Copy link
Member

@johnstcn johnstcn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, --allowed-hosts currently performs strict matching of both the host and port. This is unintuitive and as far as I can tell other frameworks match just on the hostname and not the port. For example, Rails' ActionDispatch::HostAuthorization middleware appears to strip the port before matching the host header.

@hugodutka hugodutka force-pushed the hugodutka/allowed-hosts branch from 8f2d898 to d2400b9 Compare August 8, 2025 18:10
@@ -141,17 +155,17 @@ func TestServerCmd_AllArgs_Defaults(t *testing.T) {
{"chat-base-path default", FlagChatBasePath, "/chat", func() any { return viper.GetString(FlagChatBasePath) }},
{"term-width default", FlagTermWidth, uint16(80), func() any { return viper.GetUint16(FlagTermWidth) }},
{"term-height default", FlagTermHeight, uint16(1000), func() any { return viper.GetUint16(FlagTermHeight) }},
{"allowed-hosts default", FlagAllowedHosts, []string{"localhost"}, func() any { return viper.GetStringSlice(FlagAllowedHosts) }},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also allow 127.0.0.1 and [::1] by default?

Comment on lines 120 to 133
if len(input) == 0 {
return fmt.Errorf("the list must not be empty")
}
for _, item := range input {
for _, r := range item {
if unicode.IsSpace(r) {
return fmt.Errorf("'%s' contains whitespace characters, which are not allowed", item)
}
}
if strings.Contains(item, ",") {
return fmt.Errorf("'%s' contains comma characters, which are not allowed", item)
}
}
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we validate AllowedOrigins in the HTTP layer but AllowedHosts here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We validate both in both the HTTP layer and the cmd layer. Originally because I wanted to keep cmd-specific validation, like whitespace and comma detection, to the cmd layer. But it did lead to a bunch of duplication, which I'm not happy about. I'll refactor to keep validation in a single place.

Copy link
Member

@johnstcn johnstcn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any further blocking comments.

Copy link

@jdomeracki-coder jdomeracki-coder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@hugodutka hugodutka merged commit 5c425c6 into main Aug 11, 2025
2 checks passed
hugodutka added a commit to coder/registry that referenced this pull request Aug 11, 2025
Since coder/agentapi#49 was merged, agentapi by
default only accepts requests with the `Host` header set to localhost,
127.0.0.1, or [::1]. In Coder, agentapi is served behind a reverse proxy
as a workspace app, so we need to use a wildcard
`AGENTAPI_ALLOWED_HOSTS` for agentapi-based modules to continue working.

This PR updates the claude code and agentapi modules, and a subsequent
PR will update modules that are based on the agentapi module.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants